package com.xbongbong.paas.service.async;

import com.alibaba.dingtalk.openapi.exception.OApiException;
import com.alibaba.dingtalk.openapi.exception.OApiResultException;
import com.alibaba.dingtalk.openapi.helper.DepartmentHelper;
import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.dingtalk.openapi.helper.EventChangeHelper;
import com.alibaba.dingtalk.openapi.helper.MicroAppHelper;
import com.alibaba.dingtalk.openapi.helper.UserHelper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.help.menu.CompanyInitMenuHelp;
import com.xbongbong.paas.help.menu.InitIndexConfigAndChartHelp;
import com.xbongbong.paas.model.FineClueCompanyModel;
import com.xbongbong.paas.model.FineClueUserModel;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.CallCenterCommonService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.domain.entity.FineClueCompanyEntity;
import com.xbongbong.pro.domain.entity.FineClueUserEntity;
import com.xbongbong.pro.enums.FineClueEnum;
import com.xbongbong.pro.enums.menu.enums.FineClueFormEnum;
import com.xbongbong.pro.menu.pojo.dto.CompanyMenuInitDTO;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CallCenterAccountEntity;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.help.CompanyVisibleScopesHelper;
import com.xbongbong.saas.model.CallCenterAccountModel;
import com.xbongbong.saas.util.OrganizationUtil;
import com.xbongbong.sys.domain.entity.CompanyEntity;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.FeeCompanyEntity;
import com.xbongbong.sys.domain.entity.RegisteredCallBackEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.CompanyModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.FeeCompanyModel;
import com.xbongbong.sys.model.RegisteredCallBackModel;
import com.xbongbong.sys.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.paas.redis.RedisPrefixConstant.DEPARTMENT_REFRESH_STATUS;
import static com.xbongbong.paas.redis.RedisTimeConstant.SYNC_STATUS_TIME;

/**
 * IsvReceive 异步逻辑
 * @author kaka
 * @date 2019/4/26 15:51
 * @since v1.0
 * @version v1.0
 */
@Component("isvReceiveAsync")
public class IsvReceiveAsync {

    private static final Logger LOG = LoggerFactory.getLogger(IsvReceiveAsync.class);

    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private CompanyVisibleScopesHelper companyVisibleScopesHelper;
    @Resource
    private CompanyInitMenuHelp companyInitMenuHelp;

    @Resource
    private CompanyModel companyModel;
    @Resource
    private FeeCompanyModel feeCompanyModel;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private RegisteredCallBackModel registeredCallBackModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private UserModel userModel;
    @Resource
    private CallCenterAccountModel callCenterAccountModel;
    @Resource
    private CallCenterCommonService callCenterCommonService;
    @Resource
    private InitIndexConfigAndChartHelp initIndexConfigAndChartHelp;
    @Resource
    private FineClueUserModel fineClueUserModel;
    @Resource
    private FineClueCompanyModel fineClueCompanyModel;
    
    
    /* ================================================== 异步方法 ==================================================*/

    /**
     * 手动触发组织架构同步
     * @param accessToken accessToken
     * @param updateCorpid 进行组织架构同步的公司id
     */
    @Async(value = "manualSyncOrgPool")
    public void manualSyncOrgThread(String accessToken, String updateCorpid) {
        JSONObject syncStatus = new JSONObject();
        try {
            //先设置同步中
            syncStatus.put("code", 2);
            syncStatus.put("msg", "组织架构同步中");
            paasRedisHelper.setValue(DEPARTMENT_REFRESH_STATUS, updateCorpid, syncStatus, SYNC_STATUS_TIME);

            // 更新部门的时候更新公司
            // 获取当前的suiteToken
            Object value = paasRedisHelper.getSuiteTokenValue(RedisPrefixConstant.DINGTALK_TICKET, "suiteToken");
            String suiteTokenPerm = value.toString();
            CompanyEntity updateCompany = companyModel.updateCompanyInfo(updateCorpid, suiteTokenPerm);
            if(updateCompany == null) {
                syncStatus.put("code", 3);
                syncStatus.put("msg", "更新公司信息失败");
                paasRedisHelper.setValue(DEPARTMENT_REFRESH_STATUS, updateCorpid, syncStatus, SYNC_STATUS_TIME);
                return;
            }
            String corpName = updateCompany.getCorpName();
            //更新feecompany的corpname
            Map<String,Object> param = new HashMap<>();
            param.put("corpid", updateCorpid);
            param.put("del", 0);

            List<FeeCompanyEntity> feeCompanys = feeCompanyModel.findEntitys(param);
            if(feeCompanys!=null && feeCompanys.size()>0){
                if (corpName != null) {
                    for (FeeCompanyEntity feeCompanyEntity : feeCompanys) {
                        if (!updateCompany.getCorpName().equals(feeCompanyEntity.getCorpName())) {
                            feeCompanyEntity.setMemo(feeCompanyEntity.getMemo() + ",原公司名："+feeCompanyEntity.getCorpName());
                            feeCompanyEntity.setCorpName(updateCompany.getCorpName());
                            feeCompanyModel.update(feeCompanyEntity);
                        }
                    }
                }
            }
            //修改获取部门树
            createSimpleDepTree(accessToken, updateCorpid, corpName);
            //通过可见范围,同步部门、员工详情，并刷新其可见范围
            companyVisibleScopesHelper.setCompanyVisibleScopes(updateCorpid);

            syncStatus.put("code", 1);
            syncStatus.put("msg", "组织架构同步完成");
            paasRedisHelper.setValue(DEPARTMENT_REFRESH_STATUS, updateCorpid, syncStatus, SYNC_STATUS_TIME);
            LOG.info(updateCorpid + "组织架构同步完成");

            // 手动同步组织架构之后，删除呼叫中心离职员工
            callCenterAccountAsync(updateCorpid);
            LOG.info(updateCorpid + "呼叫中心离职员工同步完成");
            /*==========================================日志=================================================*/
//						String opUserName = userEntity == null? "" : userEntity.getName();
//						String opObjectId = updateCompany.getCorpid();
//						String opObjectName = updateCompany.getCorpName();
//						Integer opModuleCode = OperateModuleTypeEnum.ORGANIZATIONAL_STRUCTURE.getCode();
//						Integer opTypeCode = OperateTypeEnum.SET.getCode();
//						String memo = opUserName + "同步了组织架构，刷新了可见范围";
//						sysLogListener.buildLog(updateCorpid, userId, opUserName, opObjectId, opObjectName, opModuleCode, opTypeCode, memo, request, null, null);
            /*===============================================================================================*/
        } catch (Exception e) {
            LOG.error("/dingtalk/syncDepartmentUser过程出错", e);
            syncStatus.put("code", 4);
            syncStatus.put("msg", "组织架构同步失败");
            paasRedisHelper.setValue(DEPARTMENT_REFRESH_STATUS, updateCorpid, syncStatus, SYNC_STATUS_TIME);
        }
    }

    /**
     * 收到钉钉修改可见范围回调异步逻辑
     * @param accessToken accessToken
     * @param corpId 公司id
     * @param corpName 公司名
     */
    @Async(value = "fetchDingDeptAndUserPool")
    public void changeAuthThread(String accessToken, String corpId, String corpName) {
        try {
            LOG.info("Runnable accessToken :" + accessToken);
            //修改获取部门树
            createSimpleDepTree(accessToken, corpId, corpName);
            //通过可见范围,同步部门、员工详情，并刷新其可见范围
            companyVisibleScopesHelper.setCompanyVisibleScopes(corpId);

            LOG.info("授权同步线程执行完毕---如果需要调试请查看error.log查看是否有错误信息");

        } catch (Exception e) {
            LOG.error("授权变更过程出错", e);
        }
    }

    /**
     * 授权时同步组织架构异步操作
     * @param xbbFrom 为空表示从钉钉过来的回调，为xbb则是saas项目过来的调用
     * @param accessToken accessToken
     * @param company 公司实体
     */
    @Async(value = "fetchDingDeptAndUserPool")
    public void authCompanyThread(String xbbFrom, String accessToken, CompanyEntity company) {
        String corpId = company.getCorpid();
        String corpName = company.getCorpName();
        if (StringUtil.isEmpty(xbbFrom)) {
            try {
                registerCallBack(accessToken, corpId);
            } catch (Exception e){
                LOG.error(corpId+"授权初始化过程，registerCallBack error", e);
            }
        }

        try {
            JSONObject userIInfo = UserHelper.getCompanyUsers(accessToken);
            if (Objects.nonNull(userIInfo)) {
                Integer count = userIInfo.getInteger("count");
                if (Objects.nonNull(count)) {
                    company.setUserNum(count);
                    companyModel.update(company);
                }
            }
        } catch (OApiException e) {
            LOG.error(corpId + "授权初始化过程OApi，update company userNum error", e);
        } catch (Exception e) {
            LOG.error(corpId + "授权初始化过程，update company userNum error", e);
        }

        try {
            //修改获取部门树
            createSimpleDepTree(accessToken, corpId, corpName);
            //通过可见范围,同步部门、员工详情，并刷新其可见范围
            companyVisibleScopesHelper.setCompanyVisibleScopes(corpId);
        } catch (OApiException e){
            LOG.error(corpId + "授权初始化过程OApi，createSimpleDepTree error", e);
        } catch (Exception e) {
            LOG.error(corpId + "授权初始化过程，createSimpleDepTree error", e);
        }

        try {
            //模板初始化
            CompanyMenuInitDTO companyMenuInitDTO = new CompanyMenuInitDTO();
            companyMenuInitDTO.setCorpid(corpId);
            companyMenuInitDTO.setUserId("");

            companyInitMenuHelp.initMenu(companyMenuInitDTO);
        } catch (Exception e){
            LOG.error(corpId + "授权初始化过程，companyInitMenuHelp.initMenu error", e);
        }

        try {
            // 首页及报表报表分类初始化
            initIndexConfigAndChartHelp.initConfig(corpId);
        } catch (Exception e){
            LOG.error(corpId + "授权初始化过程，initIndexConfigAndChartHelp.initConfig error", e);
        }

        LOG.info("授权同步线程执行完毕---如果需要调试请查看error.log查看是否有错误信息");
    }

    /* ================================================== private 方法 ==================================================*/

    /**
     * 注册通讯录回调事件
     *
     * @param accessToken
     * @param corpId
     */
    private void registerCallBack(final String accessToken, final String corpId) {
        /*
         * 构建监听的事件类型,现在只监听通讯录事件回调 user_add_org : 通讯录用户增加 user_modify_org :
         * 通讯录用户更改 user_leave_org : 通讯录用户离职 org_admin_add ：通讯录用户被设为管理员
         * org_admin_remove ：通讯录用户被取消设置管理员 org_dept_create ： 通讯录企业部门创建
         * org_dept_modify ： 通讯录企业部门修改 org_dept_remove ： 通讯录企业部门删除 org_remove ：
         * 企业被解散
         */
        List<String> callBackTag = new ArrayList<String>();
        callBackTag.add("user_add_org");
        callBackTag.add("user_modify_org");
        callBackTag.add("user_leave_org");
        callBackTag.add("org_admin_add");
        callBackTag.add("org_admin_remove");
        callBackTag.add("org_dept_create");
        callBackTag.add("org_dept_modify");
        callBackTag.add("org_dept_remove");
        callBackTag.add("org_remove");
        
        callBackTag.add("chat_add_member");
        callBackTag.add("chat_remove_member");
        callBackTag.add("chat_quit");
        callBackTag.add("chat_update_owner");
        callBackTag.add("chat_update_title");
        callBackTag.add("chat_disband");
        callBackTag.add("chat_template_change");
    
    
        // 回调地址
        String url = Env.LOCAL_URL + Env.CALL_BACK_URL;

        // 解除注册的回调事件，分开try catch是为了防止解除的错误导致后面的注册事件失败
        try {
            EventChangeHelper.deleteEventChange(accessToken);
        } catch (OApiException e) {
            if (e.getErrCode() == 71007) {
                LOG.warn("回调地址已不存在！不需要删除,corpid = " + corpId);
            } else {
                LOG.error("解除注册的回调事件时出现了其他错误", e);
            }

        }

        String retCode = null;
        try {
            retCode = EventChangeHelper.registerEventChange(accessToken,
                    callBackTag, Env.TOKEN, Env.ENCODING_AES_KEY, url);
        } catch (OApiException e) {
            LOG.error("EventChangeHelper.registerEventChange 出错:", e);
        }

        if ("1".equals(retCode)) {
            RegisteredCallBackEntity rcbEntity = registeredCallBackModel
                    .getByKey(corpId);

            if (rcbEntity == null) {
                rcbEntity = new RegisteredCallBackEntity();
            } else {
                rcbEntity.setUpdateTime(DateUtil.getInt());
            }

            rcbEntity.setUrl(Env.LOCAL_URL + Env.CALL_BACK_URL);
            rcbEntity.setCallBackTag(JSON.toJSONString(callBackTag));
            rcbEntity.setCorpid(corpId);

            try {
                registeredCallBackModel.save(rcbEntity);
            } catch (Exception e) {
                LOG.error("registeredCallBackModel.insert(rcbEntity); 出错啦！", e);
            }
        }
    }


    /**
     * 从钉钉接口/department/list中获取简单的部门列表，初步创建部门树
     * @param accessToken
     * @param corpid
     * @return 部门id集合
     * @throws OApiException
     */
    private List<Long> createSimpleDepTree(final String accessToken,
                                           final String corpid, String corpName) throws OApiException, XbbException {

        JSONObject authScopes = null;
        try {
            authScopes = MicroAppHelper.getAuthScopes(accessToken);
        } catch(OApiResultException e) {
            LOG.error("获取通讯录权限时出错", e);
        }

        if(authScopes != null) {
            JSONObject authOrgScopes = authScopes.getJSONObject("auth_org_scopes");
            if(authOrgScopes != null) {
                //授权部门
                List<Long> authedDept = JSON.parseArray(authOrgScopes.getString("authed_dept"), Long.class);

                companyConfigModel.save(corpid, CompanyConfigEnum.AUTH_ORG_SCOPES.getAlias(),
                        CompanyConfigEnum.AUTH_ORG_SCOPES.getName(), authOrgScopes.toJSONString());

                //只有在授权范围没有全公司的时候，创建部分的部门树
                if(!authedDept.contains(1L)) {
                    return createSimplePartDepTree(accessToken, corpid, authedDept, corpName);
                }
            }
        }
        //其他情况都走创建完整部门树都逻辑
        return createSimpleCompleteDepTree(accessToken, corpid);
    }

    /**
     * 创建部分部门树，当可见范围为非公司根节点，则虚挂在原父部门下，路由不在这边处理
     *
     *                          根
     *                A          B          C       D(不在授权范围的虚节点，以下部门虚挂)
     *          A1   A2      B1  B2     C1  C2      D1
     *                                          D11 D12
     *
     *
     *
     * @param accessToken
     * @param corpid
     * @param authedDept
     * @return
     * @throws OApiException
     * 创建时间 2019/1/29 2:02 PM
     * 修改时间 2019/1/29 2:02 PM
     * @author chy
     * @since v3.37
     * @version v3.37
     */
    private List<Long> createSimplePartDepTree(final String accessToken, final String corpid,
                                               final List<Long> authedDept, String corpName) throws XbbException {
        Map<Long, JSONObject> ddDepIdDepartmentMap = new HashMap<>();
        //追加公司根节点
        JSONObject companyRoot = new JSONObject();
        companyRoot.put("id", 1L);
        companyRoot.put("name", corpName);
        companyRoot.put("parentid", 0L);
        ddDepIdDepartmentMap.put(1L, companyRoot);
        //从钉钉获取部门信息
        for (Long depId : authedDept) {
            //说明有更高的节点已经被遍历
            if (ddDepIdDepartmentMap.containsKey(depId)) {
                continue;
            }
            //父节点处理
            JSONObject department = null;
            try {
                //这个接口包含所有DepartmentHelper.listDepartments的信息
                department = DepartmentHelper.getDepartment(accessToken,
                        depId.toString());
                //父节点挂在公司下面
//                department.put("parentid", 1L);
            } catch (OApiException e) {
                LOG.error("DepartmentHelper.getDepartment 从钉钉获取部门信息失败！", e);
            }
            if (department == null) {
                continue ;
            }
            ddDepIdDepartmentMap.put(depId, department);
            //子节点处理
            JSONArray childDepartments = null;
            try {
                childDepartments = DepartmentHelper.listDepartments(accessToken, depId);
            } catch (OApiException e) {
                LOG.error("DepartmentHelper.listDepartments 从钉钉获取部门信息失败！", e);
            }
            if (childDepartments == null) {
                continue ;
            }
            //遍历所有节点，将不应该挂在公司节点下的节点修正
            for (Object childDepartmentObject : childDepartments){
                JSONObject childDepartmentJson = (JSONObject)childDepartmentObject;
                Long childDepId = childDepartmentJson.getLong("id");
                JSONObject temDep = ddDepIdDepartmentMap.get(childDepId);
                //在map中已存在，且被挂在了跟节点下，则要更新父节点
                if (temDep != null && Objects.equals(temDep.getLong("parentid"), 1L)) {
                    temDep.put("parentid", childDepartmentJson.getLong("parentid"));
                    ddDepIdDepartmentMap.put(childDepId, temDep);
                } else {
                    ddDepIdDepartmentMap.put(childDepId, childDepartmentJson);
                }
            }
        }
        //获取钉钉同步到的部门id
        List<Long> depIdIn = new ArrayList<>(ddDepIdDepartmentMap.keySet());
        //获取部门的Map
        Map<Long, DepartmentEntity> deptsMap = departmentModel.getDeptsMap(corpid, depIdIn);
        // 构建depId,pid键值对，用于计算depIdRouter
        Map<Long, Long> depIdPIdMap = new HashMap<>();
        // 需要插入的部门列表
        List<DepartmentEntity> insertDeps = new LinkedList<>();
        // 需要更新的部门列表
        List<DepartmentEntity> updateDeps = new LinkedList<>();
        //将钉钉获取的部门信息保存入数据库
        for (Long depId : depIdIn) {
            JSONObject depSimple = ddDepIdDepartmentMap.get(depId);
            if (depSimple == null) {
                continue ;
            }
            DepartmentEntity depEntity = deptsMap.get(depId);
            //将简单的部门信息添加到insertDeps， updateDeps中
            depEntity = addSimpleDepToDeps(corpid, depSimple, depEntity, insertDeps, updateDeps);
            //将depId,pid键值对存入depIdPIdMap
            depIdPIdMap.put(depEntity.getId(), depEntity.getParentId());
        }
        // 插入队列中的元素计算depIdRouter并插入数据库
        for (DepartmentEntity insertDep : insertDeps) {
            OrganizationUtil.setDepIdRouter(insertDep, depIdPIdMap);
            departmentModel.insert(insertDep);
        }

        // 需要更新的部门列表
        for (DepartmentEntity updateDep : updateDeps) {
            OrganizationUtil.setDepIdRouter(updateDep, depIdPIdMap);
            departmentModel.update(updateDep);
        }

        //将不在depIdList中的部门设置del=1
        Integer del = 1;
        Integer nowInt = DateUtil.getInt();
        departmentModel.batchUpdateDelNotIn(del, nowInt, depIdIn, corpid);
        return depIdIn;
    }

    /**
     * 将简单的部门信息添加到列表
     * @param corpid
     * @param depSimple
     * @param depEntity
     * @param insertDeps
     * @param updateDeps
     * @return
     * 创建时间 2019/1/29 11:14 AM
     * 修改时间 2019/1/29 11:14 AM
     * @author chy
     * @since v3.37
     * @version v3.37
     */
    private DepartmentEntity addSimpleDepToDeps(String corpid, JSONObject depSimple, DepartmentEntity depEntity,
                                                List<DepartmentEntity> insertDeps, List<DepartmentEntity> updateDeps){
        boolean insertDepartment = false;
        if (depEntity == null) {
            depEntity = new DepartmentEntity();
            depEntity.setCorpid(corpid);
            insertDepartment = true;
        }

        depEntity = simpleDepFormat(depSimple, depEntity);

        // 此处id不会是0所以不要用save
        if (insertDepartment) {
            // 存入[插入队列]
            insertDeps.add(depEntity);
        } else {
            updateDeps.add(depEntity);
        }
        return depEntity;
    }

    /**
     * 简单的部门信息初始化部门
     * @param depSimple
     * @param depEntity
     * @return
     * 创建时间 2019/1/29 11:13 AM
     * 修改时间 2019/1/29 11:13 AM
     * @author chy
     * @since v3.37
     * @version v3.37
     */
    private DepartmentEntity simpleDepFormat(JSONObject depSimple, DepartmentEntity depEntity){
        Long depId = depSimple.getLong("id");
        depEntity.setId(depId);
        depEntity.setName(depSimple.getString("name"));
        depEntity.setParentId(depSimple.getLongValue("parentid"));

        int createDeptGroup = "true".equals(depSimple
                .getString("createDeptGroup")) ? 1 : 0;
        depEntity.setCreateDeptGroup(createDeptGroup);

        int autoAddUser = "true".equals(depSimple
                .getString("autoAddUser")) ? 1 : 0;
        depEntity.setAutoAddUser(autoAddUser);

        depEntity.setSort(0);
        depEntity.setDeptHiding(0);
        depEntity.setDeptPerimits("");
        depEntity.setUserPerimits("");
        depEntity.setOuterDept(0);
        depEntity.setOuterPermitDepts("");
        depEntity.setOuterPermitUsers("");
        depEntity.setOrgDeptOwner("");
        depEntity.setDeptManagerUseridList("");
        depEntity.setDepIdRouter("");
        depEntity.setUpdateTime(DateUtil.getInt());
        // 设置del为0
        depEntity.setDel(0);
        return depEntity;
    }

    /**
     * 创建完整的部门树
     * @param accessToken
     * @param corpid
     * @return
     * @throws OApiException
     * 创建时间 2019/1/29 1:59 PM
     * 修改时间 2019/1/29 1:59 PM
     * @author chy
     * @since v3.37
     * @version v3.37
     */
    private List<Long> createSimpleCompleteDepTree(final String accessToken,
                                                   final String corpid) throws OApiException, XbbException {


        List<Long> depIdList = new ArrayList<>();
        JSONArray departments = DepartmentHelper.listDepartments(accessToken);

        //获取部门的Map,完整的部门树，在数据库中数据匹配率较高，不传depIdIn，查处全公司部门信息
        Map<Long, DepartmentEntity> deptsMap = departmentModel.getDeptsMap(corpid, null);
        // 构建depId,pid键值对，用于计算depIdRouter
        Map<Long, Long> depIdPIdMap = new HashMap<>();
        // 需要插入的部门列表
        List<DepartmentEntity> insertDeps = new LinkedList<>();
        // 需要更新的部门列表
        List<DepartmentEntity> updateDeps = new LinkedList<>();

        //将钉钉获取的部门信息保存入数据库
        for (int i = 0; i < departments.size(); i++) {
            JSONObject depSimple = departments.getJSONObject(i);
            Long depId = depSimple.getLong("id");
            DepartmentEntity depEntity = deptsMap.get(depId);

            //将简单的部门信息添加到insertDeps， updateDeps中
            depEntity = addSimpleDepToDeps(corpid, depSimple, depEntity, insertDeps, updateDeps);

            //将部门id置入返回的列表
            depIdList.add(depId);
            // 将depId,pid键值对存入depIdPIdMap
            depIdPIdMap.put(depEntity.getId(), depEntity.getParentId());

            //将在钉钉授权范围到部门信息录入后从map中移除，剩余的是不在钉钉授权范围的，需要删除
            deptsMap.remove(depId);
        }
        // 插入队列中的元素计算depIdRouter并插入数据库
        for (DepartmentEntity insertDep : insertDeps) {
            OrganizationUtil.setDepIdRouter(insertDep, depIdPIdMap);
            departmentModel.insert(insertDep);
        }

        // 需要更新的部门列表
        for (DepartmentEntity updateDep : updateDeps) {
            OrganizationUtil.setDepIdRouter(updateDep, depIdPIdMap);
            departmentModel.update(updateDep);
        }

        //将在数据库中但不在授权范围中的数据设置为del=1
        Set<Long> depIdSet =  deptsMap.keySet();
        if (!depIdSet.isEmpty()) {
            List<Long> depIdIn = new ArrayList<>(depIdSet);
            Integer del = 1;
            Integer nowInt = DateUtil.getInt();
            departmentModel.batchUpdateDel(del, nowInt, depIdIn, corpid);
        }

        return depIdList;
    }

    /**
     * 手动同步组织架构之后，删除呼叫中心离职员工
     * @param corpid
     * @throws XbbException
     */
    private void callCenterAccountAsync(String corpid) throws XbbException{
        // 查询同步组织架构之后的人员id
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        List<UserEntity> userList = userModel.findEntitys(param);
        List<String> userIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        userList.forEach(user -> userIdList.add(user.getUserId()));

        // 查询是否开启呼叫中心
        Map<String, Object> appParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        appParam.put("corpid", corpid);
        List<String> aliasIn = new ArrayList<>();
        aliasIn.add(StringConstant.PLATFORM_DUYAN);
        aliasIn.add(StringConstant.PLATFORM_XBB);
        aliasIn.add(XbbRefTypeEnum.SEARCH_CUSTOMER.getAlias());
        aliasIn.add(XbbRefTypeEnum.FINE_CLUE.getAlias());
        appParam.put("aliasIn", aliasIn);
        appParam.put("del", DelEnum.NORMAL.getDel());
        List<PaasAppEntity> appList = paasAppModel.findEntitys(appParam);
        Boolean hasCallCenter = false;
        Boolean hasSearchCustomer = false;
        if ( CollectionsUtil.isNotEmpty(appList) ) {
            for ( PaasAppEntity paasAppEntity : appList ) {
                if ( Objects.equals(paasAppEntity.getAlias(), StringConstant.PLATFORM_DUYAN) || Objects.equals(paasAppEntity.getAlias(), StringConstant.PLATFORM_DUYAN) ) {
                    hasCallCenter = true;
                }
                if ( Objects.equals(paasAppEntity.getAlias(), XbbRefTypeEnum.FINE_CLUE.getAlias()) || Objects.equals(paasAppEntity.getAlias(), XbbRefTypeEnum.SEARCH_CUSTOMER.getAlias()) ) {
                    hasSearchCustomer = true;
                }
            }
        }
        if(hasCallCenter) {
            // 查询此时公司的坐席名单id
            Map<String, Object> callParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            callParam.put("corpid", corpid);
            callParam.put("del", DelEnum.NORMAL.getDel());
            List<CallCenterAccountEntity> callCenterAccountEntityList = callCenterAccountModel.findEntitys(callParam);
            List<String> accountIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            callCenterAccountEntityList.forEach(callCenterAccountEntity -> accountIdList.add(callCenterAccountEntity.getUserId()));

            // 求差集，离职人员id
            List<String> leaveUserIdList = accountIdList.stream().filter(num -> !userIdList.contains(num)).collect(Collectors.toList());
            for(String userId : leaveUserIdList) {
                // 清除离职话务中心角色
                LOG.info("callCenterAccountAsync---- callCenter:同步组织架构：开始清除所有话务中心角色");
                callCenterCommonService.removeCallCenterPosition(corpid, userId);
            }
        }
        if(hasSearchCustomer) {
            // 查询此时公司的坐席名单id
            Map<String, Object> callParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            callParam.put("corpid", corpid);
            callParam.put("del", DelEnum.NORMAL.getDel());
            List<FineClueUserEntity> fineClueUserList = fineClueUserModel.findEntitys(callParam);
            List<String> accountIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            fineClueUserList.forEach(fineClueUser -> accountIdList.add(fineClueUser.getUserId()));
            // 求差集，离职人员id
            List<String> leaveUserIdList = accountIdList.stream().filter(num -> !userIdList.contains(num)).collect(Collectors.toList());
            if ( CollectionsUtil.isNotEmpty(leaveUserIdList) ) {
                // todo 石安 搜客离职
                /*
                * 思路：1.如果该公司开通了搜客，把坐席表离职人员解绑->把坐席表离职人员那条数据userId置为空，坐席关闭（同关闭坐席）
                *      2.如果该公司只开通了工商查询，坐席表不做处理(坐席表里只有一条记录)
                * */
                FineClueCompanyEntity fineClueCompanyEntity = fineClueCompanyModel.getByCorpid(corpid, FineClueEnum.FINE_CLUE.getType());
                if (Objects.nonNull(fineClueCompanyEntity)){
                    String userId = "";
                    //把userId置为""
                    fineClueUserModel.batchUpdateStaff(corpid, leaveUserIdList, FineClueFormEnum.STAFFCLOSE.getCode(),userId);
                }
//                fineClueUserModel.removeLeaveStaff(corpid,leaveUserIdList);
            }
        }
        

    }

}
